package mobile.game.core.gen.serializer;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import mobile.game.core.InputStream;
import mobile.game.core.gen.GenBase;
import mobile.game.core.interfaces.ISerilizable;
import mobile.game.core.support.ClassFinder;

/**
 * @author gaopan
 *
 * 生成CommonSerializer
 */
public class GenCommonSerializer extends GenBase {
	private static final String GEN_CLASS_NAME = "CommonSerializer";
	private static final String FTL_FILE_NAME = "CommonSerializer.ftl";
	private static final Class<?> ANNO_CLASS = ISerilizable.class;
	
	private String findPackage;

	public GenCommonSerializer(String findPackage, String genPackage, String targetDir) throws Exception {
		super(genPackage, targetDir);
		
		this.findPackage = findPackage;
		this.init();
	}
	
	/**
	 * 初始化class信息，是否能生成等字段
	 * @throws Exception
	 */
	private void init() throws Exception {
		/**  默认是true */
		this.canGen = true;
		
		// 遍历所有类信息, 获取模板信息, 判断是否出错, 出错则初始化异常不能生成
		List<Class<?>> classes = getClassInfoToGen();
		for(Class<?> clazz : classes) {
			try {
				this.rootMaps.add(getRootMap(clazz));
			} catch (Exception e) {
				// 如果获取模板内容异常，表示不能生成
				/**  不能生成 */
				this.canGen = false;
				System.err.println("文件存在错误，不继续进行Observer生成了，错误如下：");
				e.printStackTrace();
			}
		}
		
	}
	
	/**
	 * 生成Proxy类的核心方法
	 * @param rootMap
	 * @throws Exception
	 */
	
	@Override
	protected void genFileHandler(Map<String, Object> rootMap) throws Exception {

	}
	
	@Override
	protected void genGlobalFileHandler(Map<String, Object> rootMaps) throws Exception {
		rootMaps.put("rootClassName", GEN_CLASS_NAME);
		rootMaps.put("interfaceName", ANNO_CLASS.getName());
		
		String targetFileDir = this.targetDir + ClassFinder.packageToPath(this.packageName) + "/";
		writeFile(targetFileDir, GEN_CLASS_NAME + ".java", FTL_FILE_NAME, rootMaps);
	}

	/**
	 * 获取要生成的class及其method
	 * @return
	 * @throws Exception
	 */
	private List<Class<?>> getClassInfoToGen() throws Exception {
		List<Class<?>> result = new LinkedList<>();
		// 获取源文件夹下的所有类
		List<Class<?>> sources = ClassFinder.getAllClass(findPackage);
		
		// 遍历所有类，取出类中有@相应注解的方法
		//ClassPool pool = ClassPool.getDefault();
		for(Class<?> clazz : sources) {
			int mod = clazz.getModifiers();
			if(Modifier.isInterface(mod) || Modifier.isAbstract(mod))
				continue;
			if(!Modifier.isPublic(mod))
				continue;
			
			if(!ANNO_CLASS.isAssignableFrom(clazz)) {
				continue;
			}
			
			// 既没有默认构造函数，有没有create工厂方法
			if(!hasDefaultConstructor(clazz) && !hasCreateMethod(clazz)) {
				System.out.println("-------生成Serializer忽略" + clazz.getName() + "文件：既没有默认构造函数，有没有create工厂方法------");
				continue;
			}

			result.add(clazz);
		}
		
		return result;
	}
	
	/**
	 * 是否有默认构造函数
	 * @param clazz
	 * @param count
	 * @return
	 */
	private boolean hasDefaultConstructor(Class<?> clazz){
		Constructor<?>[] cs = clazz.getDeclaredConstructors();
		for(Constructor<?> c : cs){
			if(c.getParameterCount() == 0)
				return true;
		}
		return false;
	}
	
	/**
	 * 是否有create(工厂)方法
	 * @param clazz
	 * @return
	 */
	private boolean hasCreateMethod(Class<?> clazz) {
		try {
			Method method = clazz.getMethod("create", InputStream.class);
			int modify = method.getModifiers();
			if(Modifier.isStatic(modify) && Modifier.isPublic(modify)) {
				return true;
			}
		} catch (NoSuchMethodException e) {
			
		}
		
		return false;
	}
	
	/**
	 * 根据Class及其methods获取填充模板内容
	 * @param clazz
	 * @param methods
	 * @return
	 * @throws Exception 
	 */
	private Map<String, Object> getRootMap(Class<?> clazz) throws Exception {
		// 获取实体类名,表名,包名
  		// String packageName = clazz.getPackage().getName();
  		
		String className = clazz.getName();
		className = className.replace('$','.');
		int id = clazz.getName().hashCode();
		// 填充Map
		Map<String, Object> rootMap = new HashMap<>();
		rootMap.put("className", className);
		rootMap.put("id", String.valueOf(id));
		
		/* 判断是否有工厂方法 */
		rootMap.put("hasCreate", hasCreateMethod(clazz));
		
		return rootMap;
	}

	public static void main(String[] args) throws Exception {
		if(args.length < 3) {
			System.out.println("usage: findPackage, genPackage, targetDir");
			return;
		}
		
		//设置log4j2配置文件所需的环境变量，作用是gen的时候
		//不会报配置没找到的错误，同时有gen.log的日志记录
		System.setProperty("logFileName", "GenCommonSerializer");
		
		String findPackage = args[0];
		String genPackage = args[1];
		String targetDir = System.getProperty("user.dir") + args[2];
		
		GenBase genCommonSerializer = new GenCommonSerializer(findPackage, genPackage, targetDir);
		
		// 判断不能生成Entity
		if(!genCommonSerializer.isCanGen()) {
			System.err.println("不能生成CommonSerializer，请检查重试。。");
			return;
		}
		
		// 测试生成实体类
		genCommonSerializer.genFiles();
	}

}
